home *** CD-ROM | disk | FTP | other *** search
/ Aminet 24 / Aminet 24 (1998)(GTI - Schatztruhe)[!][Apr 1998].iso / Aminet / comm / mail / Mutt089src.lha / Mutt-0.89i-AMIGA / src / pgp.c < prev    next >
C/C++ Source or Header  |  1998-01-28  |  28KB  |  1,213 lines

  1. /*
  2.  * Copyright (C) 1996,1997 Michael R. Elkins <me@cs.hmc.edu>
  3.  * 
  4.  *     This program is free software; you can redistribute it and/or modify
  5.  *     it under the terms of the GNU General Public License as published by
  6.  *     the Free Software Foundation; either version 2 of the License, or
  7.  *     (at your option) any later version.
  8.  * 
  9.  *     This program is distributed in the hope that it will be useful,
  10.  *     but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.  *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.  *     GNU General Public License for more details.
  13.  * 
  14.  *     You should have received a copy of the GNU General Public License
  15.  *     along with this program; if not, write to the Free Software
  16.  *     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17.  */ 
  18.  
  19. /* WARNING!!!  WARNING!!!  WARNING!!!  WARNING!!!  WARNING!!!  WARNING!!!
  20.  *
  21.  * Legal for distribution in the U.S./Canada ONLY!  Exporting this file
  22.  * outside of the U.S./Canada may be in violation of ITAR regulations!
  23.  */
  24.  
  25. /*
  26.  * This file contains all of the PGP routines necessary to sign, encrypt,
  27.  * verify and decrypt PGP messages in either the new PGP/MIME format, or
  28.  * in the older Application/Pgp format.  It also contains some code to
  29.  * cache the user's passphrase for repeat use when decrypting or signing
  30.  * a message.
  31.  */
  32.  
  33. #include "mutt.h"
  34. #include "mutt_curses.h"
  35. #include "send.h"
  36. #include "pgp.h"
  37. #include "mime.h"
  38. #include "state.h"
  39. #include "parse.h"
  40.  
  41. #include <sys/wait.h>
  42. #include <string.h>
  43. #include <stdlib.h>
  44. #include <unistd.h>
  45. #include <sys/stat.h>
  46. #include <errno.h>
  47. #include <ctype.h>
  48.  
  49. #ifdef _PGPPATH
  50.  
  51.  
  52. char PgpPass[STRING];
  53. static time_t PgpExptime = 0; /* when does the cached passphrase expire? */
  54.  
  55. void pgp_void_passphrase (void)
  56. {
  57.   memset (PgpPass, 0, sizeof (PgpPass));
  58.   PgpExptime = 0;
  59. }
  60.  
  61. int pgp_valid_passphrase (void)
  62. {
  63.   time_t now = time (NULL);
  64.  
  65.   if (now < PgpExptime) return 1; /* just use the cached copy. */
  66.   pgp_void_passphrase ();
  67.  
  68.   if (mutt_get_password ("Enter PGP passphrase:", PgpPass, sizeof (PgpPass)) == 0)
  69.   {
  70.     PgpExptime = time (NULL) + PgpTimeout;
  71.     return (1);
  72.   }
  73.   else
  74.   {
  75.     PgpExptime = 0;
  76.     return (0);
  77.   }
  78.   /* not reached */
  79. }
  80.  
  81. void mutt_forget_passphrase (void)
  82. {
  83.   pgp_void_passphrase ();
  84.   mutt_message ("PGP passphrase forgotten.");
  85. }
  86.  
  87.  
  88. static struct {
  89.   enum pgp_version v;
  90.   char *s;
  91. } pgp_vstrings[] = {
  92.   { PGP2, "pgp2" },
  93.   { PGP3, "pgp3" },
  94.   { PGP3, "pgp5" },
  95.   { PGP_G10, "g10" },
  96.   { PGP_UNKNOWN, NULL}
  97. };
  98.  
  99. enum pgp_version pgp_version(void)
  100. {
  101.   int i;
  102.   
  103.   for(i = 0; pgp_vstrings[i].s; i++)
  104.   {
  105.     if(!strcasecmp(pgp_vstrings[i].s, PgpVersion))
  106.       return pgp_vstrings[i].v;
  107.   }
  108.   
  109.   return PGP_UNKNOWN;
  110. }
  111.  
  112. char *pgp_keyid(KEYINFO *k)
  113. {
  114.   if(option(OPTPGPLONGIDS))
  115.     return k->keyid;
  116.   else
  117.     return (k->keyid + 8);
  118. }
  119.  
  120. /* ----------------------------------------------------------------------------
  121.  * Routines for handing PGP input.
  122.  */
  123.  
  124. /* print the current time to avoid spoofing of the signature output */
  125. static void pgp_current_time (STATE *s)
  126. {
  127.   time_t t;
  128.   char p[STRING];
  129.  
  130.   state_puts ("[-- PGP output follows (current time: ", s);
  131.  
  132.   t = time (NULL);
  133.   strfcpy (p, asctime (localtime (&t)), sizeof (p));
  134.   p[strlen (p) - 1] = 0; /* kill the newline */
  135.   state_puts (p, s);
  136.  
  137.   state_puts (") --]\n", s);
  138. }
  139.  
  140.  
  141. /* Support for the Application/PGP Content Type. */
  142.  
  143. void application_pgp_handler (BODY *m, STATE *s)
  144. {
  145.   int needpass = -1, pgp_keyblock = 0;
  146.   int clearsign = 0;
  147.   long start_pos = 0;
  148.   long bytes, last_pos, offset;
  149.   char buf[HUGE_STRING];
  150.   char outfile[_POSIX_PATH_MAX];
  151.   char tmpfname[_POSIX_PATH_MAX];
  152.   FILE *pgpout = NULL, *pgpin, *pgperr;
  153.   FILE *tmpfp;
  154.   pid_t thepid;
  155.   
  156.  
  157.   fseek (s->fpin, m->offset, 0);
  158.   last_pos = m->offset;
  159.   
  160.   for (bytes = m->length; bytes > 0;)
  161.   {
  162.     if (fgets (buf, sizeof (buf) - 1, s->fpin) == NULL)
  163.       break;
  164.     offset = ftell (s->fpin);
  165.     bytes -= (offset - last_pos); /* don't rely on strlen(buf) */
  166.     last_pos = offset;
  167.  
  168.     if (strncmp ("-----BEGIN PGP ", buf, 15) == 0)
  169.     {
  170.       clearsign = 0;
  171.       start_pos = last_pos;
  172.  
  173.       if (strcmp ("MESSAGE-----\n", buf + 15) == 0)
  174.         needpass = 1;
  175.       else if (strcmp ("SIGNED MESSAGE-----\n", buf + 15) == 0)
  176.       {
  177.     clearsign = 1;
  178.         needpass = 0;
  179.       }
  180.       else if (!option(OPTDONTHANDLEPGPKEYS) &&
  181.            strcmp ("PUBLIC KEY BLOCK-----\n", buf + 15) == 0) 
  182.       {
  183.         needpass = 0;
  184.         pgp_keyblock =1;
  185.       } 
  186.       else
  187.       {
  188.     if (s->prefix)
  189.       state_puts (s->prefix, s);
  190.     state_puts (buf, s);
  191.     continue;
  192.       }
  193.  
  194.       if(!clearsign || s->flags & M_VERIFY)
  195.       {
  196.  
  197.     /* invoke PGP */
  198.     
  199.     mutt_mktemp (outfile);
  200.     if ((pgpout = safe_fopen (outfile, "w+")) == NULL)
  201.     {
  202.       mutt_perror (outfile);
  203.       return;
  204.     }
  205.     
  206.     mutt_mktemp (tmpfname);
  207.     if ((tmpfp = safe_fopen(tmpfname, "w+")) == NULL)
  208.     {
  209.       mutt_perror(tmpfname);
  210.       fclose(pgpout); pgpout = NULL;
  211.       return;
  212.     }
  213.     
  214.     fputs (buf, tmpfp);
  215.     while (bytes > 0 && fgets (buf, sizeof (buf) - 1, s->fpin) != NULL)
  216.     {
  217.       offset = ftell (s->fpin);
  218.       bytes -= (offset - last_pos); /* don't rely on strlen(buf) */
  219.       last_pos = offset;
  220.       
  221.       fputs (buf, tmpfp);
  222.       if ((needpass && strcmp ("-----END PGP MESSAGE-----\n", buf) == 0) ||
  223.           (!needpass 
  224.              && (strcmp ("-----END PGP SIGNATURE-----\n", buf) == 0
  225.                  || strcmp ("-----END PGP PUBLIC KEY BLOCK-----\n",buf) == 0)))
  226.         break;
  227.     }
  228.  
  229.     fclose(tmpfp);
  230.     
  231.     if ((thepid = pgp_invoke_decode (&pgpin, NULL, &pgperr, -1,
  232.                        fileno (pgpout), -1, tmpfname, needpass)) == -1)
  233.     {
  234.       fclose (pgpout); pgpout = NULL;
  235.       mutt_unlink(tmpfname);
  236.       state_puts ("[-- Error: unable to create PGP subprocess --]\n", s);
  237.       state_puts (buf, s);
  238.       continue;
  239.     }
  240.     
  241.     if (needpass)
  242.     {
  243.     if (!pgp_valid_passphrase ())
  244.         pgp_void_passphrase ();
  245.       fputs (PgpPass, pgpin);
  246.       fputc ('\n', pgpin);
  247.     }
  248.  
  249.     fclose (pgpin);
  250.     
  251.     if (s->flags & M_DISPLAY)
  252.       pgp_current_time (s);
  253.     
  254.     mutt_wait_filter (thepid);
  255.  
  256.     mutt_unlink(tmpfname);
  257.     
  258.     if (s->flags & M_DISPLAY)
  259.       mutt_copy_stream(pgperr, s->fpout);
  260.     fclose (pgperr);
  261.     
  262.     if (s->flags & M_DISPLAY)
  263.       state_puts ("\n[-- End of PGP output --]\n\n", s);
  264.       }
  265.     
  266.       if(s->flags & M_DISPLAY)
  267.       {
  268.     if (needpass)
  269.       state_puts ("[-- BEGIN PGP MESSAGE --]\n\n", s);
  270.     else if (pgp_keyblock)
  271.       state_puts ("[-- BEGIN PGP PUBLIC KEY BLOCK --]\n", s);
  272.     else
  273.       state_puts ("[-- BEGIN PGP SIGNED MESSAGE --]\n\n", s);
  274.       }
  275.  
  276.       /* Use PGP's output if there was no clearsig signature. */
  277.       
  278.       if(!clearsign)
  279.       {
  280.     fflush (pgpout);
  281.     rewind (pgpout);
  282.     while (fgets (buf, sizeof (buf) - 1, pgpout) != NULL)
  283.     {
  284.       if (s->prefix)
  285.         state_puts (s->prefix, s);
  286.       state_puts (buf, s);
  287.     }
  288.       }
  289.  
  290.       /* Close the temporary files iff they were created. 
  291.        * The condition used to be !clearsign || s->flags & M_VERIFY,
  292.        * but gcc would complain then.
  293.        */
  294.       
  295.       if(pgpout)
  296.       {
  297.     fclose (pgpout);
  298.     pgpout = NULL;
  299.     mutt_unlink(outfile);
  300.       }
  301.  
  302.       /* decode clearsign stuff */
  303.       
  304.       if(clearsign)
  305.       {
  306.  
  307.     /* rationale: We want PGP's error messages, but in the times
  308.      * of PGP 5.0 we can't rely on PGP to do the dash
  309.      * escape decoding - so we have to do this
  310.      * ourselves.
  311.      */
  312.     
  313.     int armor_header = 1;
  314.     int complete = 1;
  315.     
  316.     fseek(s->fpin, start_pos, SEEK_SET);
  317.     bytes += (last_pos - start_pos);
  318.     last_pos = start_pos;
  319.     offset = start_pos;
  320.     while(bytes > 0 && fgets(buf, sizeof(buf) - 1, s->fpin) != NULL)
  321.     {
  322.       offset = ftell(s->fpin);
  323.       bytes -= (offset - last_pos);
  324.       last_pos = offset;
  325.  
  326.       if(complete)
  327.       {
  328.         if (!strcmp(buf, "-----BEGIN PGP SIGNATURE-----\n"))
  329.           break;
  330.         
  331.         if(armor_header)
  332.         {
  333.           if(*buf == '\n')
  334.         armor_header = 0;
  335.         }
  336.         else
  337.         {
  338.           if(s->prefix)
  339.         state_puts(s->prefix, s);
  340.           
  341.           if(buf[0] == '-' && buf [1] == ' ')
  342.         state_puts(buf + 2, s);
  343.           else
  344.         state_puts(buf, s);
  345.         }
  346.       } 
  347.       else 
  348.       {
  349.         if(!armor_header)
  350.           state_puts(buf, s);
  351.       }
  352.       
  353.       complete = strchr(buf, '\n') != NULL;
  354.     }
  355.     
  356.     if (complete && !strcmp(buf, "-----BEGIN PGP SIGNATURE-----\n"))
  357.     {
  358.       while(bytes > 0 && fgets(buf, sizeof(buf) - 1, s->fpin) != NULL